<?php
error_reporting(E_ALL | E_STRICT);
ini_set("soap.wsdl_cache_enabled", false);

require_once 'WSDLParser.php';

// get config file
$ini = parse_ini_file("WSDLparser.ini", true);

$wsdlFile = $ini["generator"]["wsdlFile"];
$portType = $ini["generator"]["portType"];
$primitiveTypes = explode(",", $ini["system"]["primitiveTypes"]);
$dataTypesPrefix = $ini["generator"]["dataTypesPrefix"];
$dataTypesOutFile = $ini["generator"]["dataTypesOutFile"];
$classOutFile = $ini["generator"]["classOutFile"];

try
{
	$parser = new WSDLParser($wsdlFile, $portType, $primitiveTypes);
	
	$parser->parse();
	
	//echo "data types parsing...\n";
	$dataTypes = $parser->getDataTypes();
	
	//echo "operations parsing...\n";
	$methods = $parser->getMethods();
	
	
	$time = time();
	// рисуем типы
	$types = "<?php\n\n";
	$types .= "// Warning! This code was generated by WSDL2PHP tool. \n";
	$types .= "// author: Filippov Andrey <afi.work@gmail.com> \n";
	$types .= "// see https://solo-framework-lib.googlecode.com \n";
	$types .= "// Timestamp: {$time} \n\n";
	
	foreach ($dataTypes as $type)
	{	
		// skip primitives	
		if ($type->isPrimitive && !$type->isEnum)
			continue;

		if ($type->isEnum)
			$types .= drawEnum($type, $dataTypesPrefix);

		if (!$type->isPrimitive)	
			$types .= drawClass($type, $parser, $dataTypesPrefix);

	}	
	$types .= "?>";
	
	echo "writing {$dataTypesOutFile}...\n";
	file_put_contents($dataTypesOutFile, $types);

	// генерируем класс с методами веб-сервиса
	$template = file_get_contents("TemplateWebService.php");
	
	// replace macros	
	$template = str_replace("TIMESTAMP", $time, $template);
	$template = str_replace("/*REQUIRE_DATATYPES*/", $dataTypesOutFile, $template);
	$template = str_replace("/*CLASSNAME*/", $dataTypesPrefix, $template);
	$template = str_replace("/*CLASSMAP*/", generateClassMap($dataTypes, $dataTypesPrefix), $template);
	$template = str_replace("/*METHODS*/", generateMethods($methods, $parser, $dataTypesPrefix, $dataTypes), $template);
	
	echo "writing {$dataTypesPrefix}WebServiceConnector.php...\n";
	file_put_contents($classOutFile, $template);
	
	echo "parsing completed\n";//print_r($dataTypes);print_r($methods);
}
catch (Exception $e)
{
	echo "Error:\n" . $e->getMessage();
}


function generateMethods($methods, WSDLParser $parser, $dataTypesPrefix, $dataTypes)
{	
	$out = "";
	foreach ($methods as $key => $item)
	{
		$input = "";
		$inputParam = "";
		if ($item->inputPrimitive)
			$input = $item->input;			
		else
			$input = $inputParam = $dataTypesPrefix.$item->input;
		
		$output = "";
		if ($item->outputPrimitive)
			$output = $item->output;			
		else
			$output = $dataTypesPrefix.$item->output;

		$isMessagePart = @$dataTypes[$item->input]->isMessagePart;
	
		if ($isMessagePart)
		{
		$out .= <<<METHOD

	/**
	 * {$item->operationDoc}
	 * 
	 * @param {$input} \$request
	 * 
	 * @return {$output}
	 */
	public function {$key}({$inputParam} \$request)
	{
		\$request = (array)\$request;
		return \$this->call(__FUNCTION__, \$request);
	}

METHOD;
		}
		else 
		{
		
		$out .= <<<METHOD

	/**
	 * {$item->operationDoc}
	 * 
	 * @param {$input} \$request
	 * 
	 * @return {$output}
	 */
	public function {$key}({$inputParam} \$request)
	{
		\$request = array(\$request);
		return \$this->call(__FUNCTION__, \$request);
	}

METHOD;
		}
	}
	
	return $out;
}

function generateClassMap($dataTypes, $dataTypesPrefix)
{
	$res = "";
	foreach ($dataTypes as $key => $type)
		$res .= "\n\t\t\t'{$key}' => '{$dataTypesPrefix}{$key}',";
	return $res;
}

/**
 * Генерация сеттеров для списочных переменных
 * 
 * @param $name
 * @param $type
 * @param $doc
 */
function generateAdditionalCode($name, $type, $doc)
{
	$method = ucfirst($name);
	$out = <<<OUT

	/**
	 * {$doc}
	 * 
	 * @param {$type}
	 *
	 * @return void
	 */
	public function add{$method}({$type} \$item)
	{
		\$this->{$name}[] = \$item;
	}

OUT;
	return $out;
}


/**
 * Отрисовка кода класса
 * 
 * @param $type
 * @param WSDLParser $parser
 */
function drawClass($type, WSDLParser $parser, $dataTypesPrefix)
{
	$attr = "";
	foreach ($type->attributes as $atribute)
	{
		$attrType = $parser->findFinalType($atribute->type);
		if (!$parser->isPrimitive($attrType))
			$attrType = $dataTypesPrefix.$attrType;
		
	$attr .= <<<ATTR
	
	/**
	 * {$atribute->doc}
	 * 
	 * @var {$attrType}
	 */
	 public \${$atribute->name} = null;
	
ATTR;

		if ($atribute->maxOccurs == "unbounded")
			$attr .= generateAdditionalCode($atribute->name, $attrType, $atribute->doc);
	}
	
	$baseType = "";
	if ($type->baseType)
		$baseType = " extends {$dataTypesPrefix}{$type->baseType}";

	$class = <<<CLASS
	
/**
 * {$type->classDoc}
 */	
class {$dataTypesPrefix}{$type->className}{$baseType}
{
	{$attr}
}
	
CLASS;

	return $class;
}


/**
 * Отрисовка ENUM
 * 
 * @param $type
 */
function drawEnum($type, $dataTypesPrefix)
{	
	$const = "";
	foreach ($type->enumeration as $enum)
	{
		// т.к. цифры не могут быть именами переменных, добавляем имя класса
		$attrName = $enum->value;
		if(preg_match('/[\d]+/', $attrName))
			$attrName = "{$type->className}{$enum->value}";
		
		// drawing enumeration
		$const .= <<<CONST

	/**
	 * {$enum->comment}
	 * 
	 * @var {$type->baseType}
	 */
	const {$attrName} = '{$enum->value}';

CONST;
	}
	
	
	// drawing body of class
	$out = <<<ENUM

/**
 * {$type->classDoc}
 */
class {$dataTypesPrefix}{$type->className}
{
{$const}
}

ENUM;
	return $out;
}


?>